%{
    #include "common.h"
    #include "syntax-tree.h"
    #define YYDEBUG 1
    extern void yyerror(const char * msg);
    int yylex();
%}

%union {
    tree_node *t;
}

%locations
%define parse.error verbose
%token <t> INT <t> FLOAT <t> ID
%token <t> SEMI <t> COMMA <t> ASSIGNOP <t> RELOP <t> PLUS <t> MINUS
%token <t> STAR <t> DIV <t> AND <t> OR <t> DOT <t> NOT <t> TYPE
%token <t> LP <t> RP <t> LB <t> RB <t> LC <t> RC
%token <t> STRUCT <t> RETURN <t> IF <t> ELSE <t> WHILE

%type <t> Program <t> ExtDefList <t> ExtDef <t> ExtDecList
%type <t> Specifier <t> StructSpecifier <t> OptTag <t> Tag
%type <t> VarDec <t> FunDec <t> VarList <t> ParamDec
%type <t> CompSt <t> StmtList <t> Stmt
%type <t> DefList <t> Def <t> DecList <t> Dec
%type <t> Exp <t> Args

%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

%left COMMA
%right ASSIGNOP
%left OR
%left AND
%left RELOP
%left PLUS MINUS
%left STAR DIV
%right NOT HIHGER_THAN_MINUS
%left LP RP LB RB DOT

%%
Program : ExtDefList {
            root=$$=treeNodeInit(CYF_Program,@$.first_line,1);
            $$->info=str_maker("Program (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;
ExtDefList : {$$=treeNodeInit(CYF_ExtDefList,@$.first_line,1);}
    | ExtDef ExtDefList {
            $$=treeNodeInit(CYF_ExtDefList,@$.first_line,2);
            $$->info=str_maker("ExtDefList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    ;
ExtDef : Specifier ExtDecList SEMI {
            $$=treeNodeInit(CYF_ExtDef,@$.first_line,1);
            $$->info=str_maker("ExtDef (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Specifier SEMI {
            $$=treeNodeInit(CYF_ExtDef,@$.first_line,2);
            $$->info=str_maker("ExtDef (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    | Specifier FunDec CompSt{
            $$=treeNodeInit(CYF_ExtDef,@$.first_line,3);
            $$->info=str_maker("ExtDef (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Specifier FunDec SEMI{
            $$=treeNodeInit(CYF_ExtDef,@$.first_line,4);
            $$->info=str_maker("ExtDef (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | error SEMI {$$=treeNodeInit(CYF_ExtDef,@$.first_line,-1);$$->info=str_maker("ExtDef (%d)",@$.first_line);syntax_error=1;}
    | error RP {$$=treeNodeInit(CYF_ExtDef,@$.first_line,-1);$$->info=str_maker("ExtDef (%d)",@$.first_line);syntax_error=1;}
    | error RC {$$=treeNodeInit(CYF_ExtDef,@$.first_line,-1);$$->info=str_maker("ExtDef (%d)",@$.first_line);syntax_error=1;}
    | Specifier error LC DefList StmtList RC {$$=treeNodeInit(CYF_ExtDef,@$.first_line,-1);$$->info=str_maker("ExtDef (%d)",@$.first_line);syntax_error=1;};
    ;
ExtDecList : VarDec {
            $$=treeNodeInit(CYF_ExtDecList,@$.first_line,1);
            $$->info=str_maker("ExtDecList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | VarDec COMMA ExtDecList {
            $$=treeNodeInit(CYF_ExtDecList,@$.first_line,2);
            $$->info=str_maker("ExtDecList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    ;

Specifier : TYPE {
            $$=treeNodeInit(CYF_Specifier,@$.first_line,1);
            $$->info=str_maker("Specifier (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | StructSpecifier {
            $$=treeNodeInit(CYF_Specifier,@$.first_line,2);
            $$->info=str_maker("Specifier (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;
StructSpecifier : STRUCT OptTag LC DefList RC {
            $$=treeNodeInit(CYF_StructSpecifier,@$.first_line,1);
            $$->info=str_maker("StructSpecifier (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
            treeNodeInsert($$,$5);
        }
    | STRUCT Tag {
            $$=treeNodeInit(CYF_StructSpecifier,@$.first_line,2);
            $$->info=str_maker("StructSpecifier (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    | STRUCT OptTag LC DefList error RC {$$=treeNodeInit(CYF_StructSpecifier,@$.first_line,-1);$$->info=str_maker("StructSpecifier (%d)",@$.first_line);syntax_error=1;}
    ;
OptTag : {$$=treeNodeInit(CYF_OptTag,@$.first_line,1);}
    | ID {
            $$=treeNodeInit(CYF_OptTag,@$.first_line,2);
            $$->info=str_maker("OptTag (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;
Tag : ID {
            $$=treeNodeInit(CYF_Tag,@$.first_line,1);
            $$->info=str_maker("Tag (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;

VarDec : ID {
            $$=treeNodeInit(CYF_VarDec,@$.first_line,1);
            $$->info=str_maker("VarDec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | VarDec LB INT RB {
            $$=treeNodeInit(CYF_VarDec,@$.first_line,2);
            $$->info=str_maker("VarDec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
        }
    ;
FunDec : ID LP VarList RP {
            $$=treeNodeInit(CYF_FunDec,@$.first_line,1);
            $$->info=str_maker("FunDec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
        }
    | ID LP RP {
            $$=treeNodeInit(CYF_FunDec,@$.first_line,2);
            $$->info=str_maker("FunDec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | error RP {$$=treeNodeInit(CYF_FunDec,@$.first_line,-1);$$->info=str_maker("FunDec (%d)",@$.first_line);}
    ;
VarList : ParamDec COMMA VarList {
            $$=treeNodeInit(CYF_VarList,@$.first_line,1);
            $$->info=str_maker("VarList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | ParamDec {
            $$=treeNodeInit(CYF_VarList,@$.first_line,2);
            $$->info=str_maker("VarList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;
ParamDec : Specifier VarDec {
            $$=treeNodeInit(CYF_ParamDec,@$.first_line,1);
            $$->info=str_maker("ParamDec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    ;

CompSt : LC DefList StmtList RC {
            $$=treeNodeInit(CYF_CompSt,@$.first_line,1);
            $$->info=str_maker("CompSt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
        }
    | error RC {$$=treeNodeInit(CYF_CompSt,@$.first_line,-1);$$->info=str_maker("CompSt (%d)",@$.first_line);syntax_error=1;}
    ;
StmtList : {$$=treeNodeInit(CYF_StmtList,@$.first_line,1);}
    | Stmt StmtList {
            $$=treeNodeInit(CYF_StmtList,@$.first_line,2);
            $$->info=str_maker("StmtList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    ;
Stmt : Exp SEMI {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,1);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    | CompSt {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,2);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | RETURN Exp SEMI {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,3);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | IF LP Exp RP Stmt %prec LOWER_THAN_ELSE {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,4);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
            treeNodeInsert($$,$5);
        }
    | IF LP Exp RP Stmt ELSE Stmt {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,5);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
            treeNodeInsert($$,$5);
            treeNodeInsert($$,$6);
            treeNodeInsert($$,$7);
        }
    | WHILE LP Exp RP Stmt {
            $$=treeNodeInit(CYF_Stmt,@$.first_line,6);
            $$->info=str_maker("Stmt (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
            treeNodeInsert($$,$5);
        }
    | IF LP error RP Stmt %prec LOWER_THAN_ELSE {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | IF LP error RP Stmt ELSE Stmt {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | WHILE LP error RP Stmt {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | error SEMI {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | IF error LC StmtList RC %prec LOWER_THAN_ELSE {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | IF error LC StmtList RC ELSE Stmt {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    | WHILE error LC StmtList RC {$$=treeNodeInit(CYF_Stmt,@$.first_line,-1);$$->info=str_maker("Stmt (%d)",@$.first_line);syntax_error=1;}
    ;

DefList : {$$=treeNodeInit(CYF_DefList,@$.first_line,1);}
    | Def DefList {
            $$=treeNodeInit(CYF_DefList,@$.first_line,2);
            $$->info=str_maker("DefList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    ;
Def : Specifier DecList SEMI {
            $$=treeNodeInit(CYF_Def,@$.first_line,1);
            $$->info=str_maker("Def (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Specifier error SEMI {$$=treeNodeInit(CYF_Def,@$.first_line,-1);$$->info=str_maker("Def (%d)",@$.first_line);syntax_error=1;}
    ;
DecList : Dec {
            $$=treeNodeInit(CYF_DecList,@$.first_line,1);
            $$->info=str_maker("DecList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | Dec COMMA DecList {
            $$=treeNodeInit(CYF_DecList,@$.first_line,2);
            $$->info=str_maker("DecList (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    ;
Dec : VarDec {
            $$=treeNodeInit(CYF_Dec,@$.first_line,1);
            $$->info=str_maker("Dec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | VarDec ASSIGNOP Exp {
            $$=treeNodeInit(CYF_Dec,@$.first_line,2);
            $$->info=str_maker("Dec (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    ;
Exp : Exp ASSIGNOP Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,1);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp AND Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,2);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp OR Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,3);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp RELOP Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,4);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp PLUS Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,5);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp MINUS Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,6);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp STAR Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,7);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp DIV Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,8);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | LP Exp RP {
            $$=treeNodeInit(CYF_Exp,@$.first_line,9);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | MINUS Exp %prec HIHGER_THAN_MINUS {
            $$=treeNodeInit(CYF_Exp,@$.first_line,10);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    | NOT Exp {
            $$=treeNodeInit(CYF_Exp,@$.first_line,11);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
        }
    | ID LP Args RP {
            $$=treeNodeInit(CYF_Exp,@$.first_line,12);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
        }
    | ID LP RP {
            $$=treeNodeInit(CYF_Exp,@$.first_line,13);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp LB Exp RB {
            $$=treeNodeInit(CYF_Exp,@$.first_line,14);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
            treeNodeInsert($$,$4);
        }
    | Exp DOT ID {
            $$=treeNodeInit(CYF_Exp,@$.first_line,15);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | ID {
            $$=treeNodeInit(CYF_Exp,@$.first_line,16);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | INT {
            $$=treeNodeInit(CYF_Exp,@$.first_line,17);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | FLOAT {
            $$=treeNodeInit(CYF_Exp,@$.first_line,18);
            $$->info=str_maker("Exp (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    | LP error RP {$$=treeNodeInit(CYF_Exp,@$.first_line,-1);$$->info=str_maker("Exp (%d)",@$.first_line);syntax_error=1;}
    | ID LP error RP {$$=treeNodeInit(CYF_Exp,@$.first_line,-1);$$->info=str_maker("Exp (%d)",@$.first_line);syntax_error=1;}
    ;
Args : Exp COMMA Args {
            $$=treeNodeInit(CYF_Args,@$.first_line,1);
            $$->info=str_maker("Args (%d)",@$.first_line);
            treeNodeInsert($$,$1);
            treeNodeInsert($$,$2);
            treeNodeInsert($$,$3);
        }
    | Exp {
            $$=treeNodeInit(CYF_Args,@$.first_line,2);
            $$->info=str_maker("Args (%d)",@$.first_line);
            treeNodeInsert($$,$1);
        }
    ;
%%
#include "lex.yy.c"
void yyerror(const char * msg){
    #ifdef LESS
    printf("Error type B at Line %d",yylloc.first_line);putchar('\n');
    #else
    printf("Error type B at Line %d: %s.\n",yylloc.first_line,msg);
    #endif
    syntax_error=2;
}  
